package cn.com.cifi.mars.service.impl;

import static java.util.stream.Collectors.toList;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.com.cifi.mars.bean.dto.SupplyPlanValueDetailDto;
import cn.com.cifi.mars.bean.dto.SupplyPlanVersionDto;
import cn.com.cifi.mars.bean.vo.sys.rsp.GroupUserVo;
import cn.com.cifi.mars.constant.Constants;
import cn.com.cifi.mars.constant.IsDeleteEnum;
import cn.com.cifi.mars.constant.IsSupplyEnum;
import cn.com.cifi.mars.constant.OrgTypeEunm;
import cn.com.cifi.mars.constant.SalyTypeEnum;
import cn.com.cifi.mars.constant.VersionIdentifyEnum;
import cn.com.cifi.mars.constant.VersionTypeEunm;
import cn.com.cifi.mars.entity.DmDmSupplyConfirmReport;
import cn.com.cifi.mars.entity.DmDmSupplyConfirmReportMonth;
import cn.com.cifi.mars.entity.SupplyConfirmRecord;
import cn.com.cifi.mars.entity.SupplyConfirmRecordDetail;
import cn.com.cifi.mars.entity.SupplyPlanVersionDetail;
import cn.com.cifi.mars.mapper.mars.DmDmSupplyConfirmReportMapper;
import cn.com.cifi.mars.mapper.mars.SupplyConfirmRecordDetailMapper;
import cn.com.cifi.mars.mapper.mars.SupplyConfirmRecordMapper;
import cn.com.cifi.mars.mapper.mars.SupplyPlanVersionDetailMapper;
import cn.com.cifi.mars.mapper.mars.SupplyPlanVersionMapper;
import cn.com.cifi.mars.service.IdmUserService;
import cn.com.cifi.mars.service.SupplyConfirmRecordDetailService;
import cn.com.cifi.mars.util.LocalDateTimeUtils;
import cn.com.cifi.mars.util.NumberUtils;
import cn.com.cifi.mars.util.StrUtils;
import cn.com.cifi.mars.util.UUIDUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 供货确认记录详情表 服务实现类
 * </p>
 *
 * @author yyd
 * @since 2019-11-25
 */
@Slf4j
@Service
public class SupplyConfirmRecordDetailServiceImpl extends ServiceImpl<SupplyConfirmRecordDetailMapper, SupplyConfirmRecordDetail> implements SupplyConfirmRecordDetailService {

	@Autowired
	private SupplyConfirmRecordDetailMapper supplyConfirmRecordDetailMapper;
	
	@Autowired
	private SupplyPlanVersionDetailMapper supplyPlanVersionDetailMapper;
	
	@Autowired
	private SupplyPlanVersionMapper supplyPlanVersionMapper;
	
	@Autowired
	private SupplyConfirmRecordMapper supplyConfirmRecordMapper;
	
	@Autowired
	private DmDmSupplyConfirmReportMapper dmDmSupplyConfirmReportMapper;
	
	@Autowired
	private IdmUserService idmUserService;

	@Override
	public List<SupplyConfirmRecordDetail> queryByProjectId(String projectId, String versionDate) {
		return supplyConfirmRecordDetailMapper.selectConfirmedList(projectId,versionDate,IsDeleteEnum.NO.getKey());
	}
	
	@Override
	public SupplyPlanValueDetailDto prepareProjectYearData(String versionId, int year) {
		SupplyPlanValueDetailDto resData = new SupplyPlanValueDetailDto();
		List<SupplyPlanVersionDetail> versionDataList = supplyPlanVersionDetailMapper.selectByVersionId(versionId, IsDeleteEnum.NO.getKey());
		SupplyPlanValueDetailDto planData = getYearPlanData(versionId,year,versionDataList,resData);
		SupplyPlanValueDetailDto actualData = getYearActualData(versionId,year,versionDataList,resData);
		if(planData != null) {
			resData.setRoomNum(planData.getRoomNum());
			resData.setParkingNum(planData.getParkingNum());
			resData.setArea(planData.getArea());
			resData.setHouseCommodityValue(planData.getHouseCommodityValue());
			resData.setNotCommodityValue(planData.getNotCommodityValue());
		}
		if(actualData != null) {
			resData.setRoomNumActual(actualData.getRoomNumActual());
			resData.setParkingNumActual(actualData.getParkingNumActual());
			resData.setAreaActual(actualData.getAreaActual());
			resData.setHouseCommodityValueActual(actualData.getHouseCommodityValueActual());
			resData.setNotCommodityValueActual(actualData.getNotCommodityValueActual());
		}
		return resData;
	}


	@Override
	public SupplyPlanValueDetailDto prepareProjectMonthData(String versionId, String month) {
		 return supplyPlanVersionDetailMapper.selectStageMonthData(versionId,month,IsDeleteEnum.NO.getKey());
	}
	
	@Override
	public SupplyPlanValueDetailDto prepareAllYearData(String versionId, int year,List<SupplyPlanVersionDetail> versionDataList) {
		SupplyPlanValueDetailDto resData = new SupplyPlanValueDetailDto();
		resData = getYearPlanData(versionId,year,versionDataList,resData);
		resData = getYearActualData(versionId,year,versionDataList,resData);
		return resData;
	}
	
	private SupplyPlanValueDetailDto getYearActualData(String versionId, int year,
			List<SupplyPlanVersionDetail> versionDataList, SupplyPlanValueDetailDto resData) {
		 Integer sumRoomNum = null;
		 Integer sumParkingNum = null;
		 BigDecimal sumArea = null;
		 BigDecimal sumHouseCommodityValue = null;
		 BigDecimal sumNotCommodityValue = null;
		for(SupplyPlanVersionDetail detail : versionDataList) {
			if(detail.getVersionId().equals(versionId)) {
				LocalDateTime supplyTimeActual = detail.getSupplyTimeVirtual() == null ? detail.getSupplyDateActual() : detail.getSupplyTimeVirtual();
				if(isSameYear(supplyTimeActual,year)) {
					String businessType = detail.getBusinessType();
					if(isValid(businessType)) {
						Integer isParking = detail.getIsParking();
						 if(isParking != null && isParking.intValue() == 1) {
								detail.setAreaActual(BigDecimal.ZERO);
					     }
						sumRoomNum = NumberUtils.intADD(sumRoomNum, detail.getRoomNumActual());
						sumParkingNum = NumberUtils.intADD(sumParkingNum, detail.getParkingNumActual());
						sumArea = NumberUtils.BigDecimalADD(4, sumArea, detail.getAreaActual());
						sumHouseCommodityValue= NumberUtils.BigDecimalADD(4, sumHouseCommodityValue, detail.getHouseCommodityValueActual());
						sumNotCommodityValue= NumberUtils.BigDecimalADD(4, sumNotCommodityValue, detail.getNotCommodityValueActual());
					}
				}
			}
		}
		resData.setRoomNumActual(sumRoomNum);
		resData.setParkingNumActual(sumParkingNum);
		resData.setAreaActual(sumArea);
		resData.setHouseCommodityValueActual(sumHouseCommodityValue);
		resData.setNotCommodityValueActual(sumNotCommodityValue);
		return resData;
	}

	private SupplyPlanValueDetailDto getYearPlanData(String versionId, int year,List<SupplyPlanVersionDetail> versionDataList,SupplyPlanValueDetailDto resData) {
		 Integer sumRoomNum = 0;
		 Integer sumParkingNum = 0;
		 BigDecimal sumArea = BigDecimal.ZERO;
		 BigDecimal sumHouseCommodityValue = BigDecimal.ZERO;
		 BigDecimal sumNotCommodityValue = BigDecimal.ZERO;
		for(SupplyPlanVersionDetail detail : versionDataList) {
			if(detail.getVersionId().equals(versionId)) {
				LocalDateTime supplyTime = detail.getSupplyDate();
				if(isSameYear(supplyTime,year)) {
					String businessType = detail.getBusinessType();
					Integer isParking = detail.getIsParking();
					if(isValid(businessType)) {
						 if(isParking != null && isParking.intValue() == 1) {
							detail.setSaleArea(BigDecimal.ZERO);
							detail.setAreaActual(BigDecimal.ZERO);
						 }
						 LocalDateTime supplyTimeActual = detail.getSupplyDateActual() == null ? detail.getSupplyTimeVirtual() : detail.getSupplyDateActual();
						 Integer roomNum = detail.getRoomNum();
						 Integer parkingNum = detail.getParkingNum();
						 BigDecimal area = detail.getSaleArea();
						 BigDecimal houseCommodityValue = detail.getHouseCommodityValue();
						 BigDecimal notCommodityValue = detail.getNotCommodityValue();
						 //去除提前供货
						if(isBeforeYear(supplyTimeActual,year)) {
							roomNum = NumberUtils.subtract(roomNum, detail.getRoomNumActual());
							parkingNum = NumberUtils.subtract(parkingNum, detail.getParkingNumActual());
							area = NumberUtils.subtract(area, detail.getAreaActual());
							houseCommodityValue = NumberUtils.subtract(houseCommodityValue, detail.getHouseCommodityValueActual());
							notCommodityValue = NumberUtils.subtract(notCommodityValue, detail.getNotCommodityValueActual());
						}
						sumRoomNum = NumberUtils.intADD(sumRoomNum, roomNum);
						sumParkingNum = NumberUtils.intADD(sumParkingNum,parkingNum);
						sumArea = NumberUtils.BigDecimalADD(4, sumArea,area);
						sumHouseCommodityValue = NumberUtils.BigDecimalADD(4, sumHouseCommodityValue,houseCommodityValue);
						sumNotCommodityValue = NumberUtils.BigDecimalADD(4, sumNotCommodityValue, notCommodityValue);
					}
				}
			}
		}
		resData.setRoomNum(sumRoomNum);
		resData.setParkingNum(sumParkingNum);
		resData.setArea(sumArea);
		resData.setHouseCommodityValue(sumHouseCommodityValue);
		resData.setNotCommodityValue(sumNotCommodityValue);
		return resData;
	}
	
	private boolean isValid(String businessTypeName) {
		return StrUtils.isNotEmpty(businessTypeName) && (businessTypeName.equals(SalyTypeEnum.SALABLE.getKey()) || businessTypeName.equals(SalyTypeEnum.STAGE_SELF_SUSTAINMENT.getKey()));
	}
	
	private boolean isSameYear(LocalDateTime supplyTime ,int year) {
		return supplyTime != null && supplyTime.getYear() == year;
	}
	
	private boolean isBeforeYear(LocalDateTime supplyTime,int year) {
		return supplyTime != null && supplyTime.getYear() < year;
	}
	
	private boolean isSameMonth(LocalDateTime supplyTime,String month) {
		if(supplyTime != null) {
			String yearMonth = LocalDateTimeUtils.formatTime(supplyTime, "yyyy-MM");
			return yearMonth.equals(month);
		}
		return false;
	}

	@Override
	public SupplyPlanValueDetailDto prepareAllMonthData(String versionId, String month,List<SupplyPlanVersionDetail> versionDataList) {
		SupplyPlanValueDetailDto resData = new SupplyPlanValueDetailDto();
		Integer sumRoomNum = 0;
		Integer sumParkingNum = 0;
	    BigDecimal sumArea = BigDecimal.ZERO;
     	BigDecimal sumHouseCommodityValue = BigDecimal.ZERO;
		BigDecimal sumNotCommodityValue = BigDecimal.ZERO;
		for(SupplyPlanVersionDetail detail : versionDataList) {
			if(detail.getVersionId().equals(versionId)) {
				LocalDateTime supplyTime = detail.getSupplyDate();
				Integer isSupply = detail.getIsSupply();
				if(isSameMonth(supplyTime,month) && !isSupply(isSupply)) {
					sumRoomNum = NumberUtils.intADD(sumRoomNum, detail.getRoomNum());
					sumParkingNum = NumberUtils.intADD(sumParkingNum, detail.getParkingNum());
					sumArea = NumberUtils.BigDecimalADD(4, sumArea, detail.getSaleArea());
					sumHouseCommodityValue = NumberUtils.BigDecimalADD(4, sumHouseCommodityValue, detail.getHouseCommodityValue());
					sumNotCommodityValue = NumberUtils.BigDecimalADD(4, sumNotCommodityValue, detail.getNotCommodityValue());
				}
			}
		}
		resData.setRoomNum(sumRoomNum);
		resData.setParkingNum(sumParkingNum);
		resData.setArea(sumArea);
		resData.setHouseCommodityValue(sumHouseCommodityValue);
		resData.setNotCommodityValue(sumNotCommodityValue);
		return resData;
	}
	
	private boolean isSupply(Integer isSupply) {
		return isSupply != null && isSupply.intValue() == IsSupplyEnum.ALREADY_SUPPLIED.getKey();
	}

	@Override
	@Transactional
	public synchronized void initSupplyConfirmReport(String yearMonth, String projectId) {
		int year = Integer.parseInt(yearMonth.split("-")[0]);
		//详情页面展示的月份
    	List<String> months = getSupplyConfirmDetailMonths(yearMonth);
		String endConfirmDate = LocalDateTimeUtils.getEndConfirmDate(yearMonth);
		List<SupplyPlanVersionDto> supplyPlanVersionList = supplyPlanVersionMapper.selectConfirmVersion(projectId,yearMonth,endConfirmDate,IsDeleteEnum.NO.getKey());
		//所有版本ID
    	List<String> versionIds = supplyPlanVersionList.stream().map(SupplyPlanVersionDto::getId).collect(toList());
    	if(CollectionUtils.isNotEmpty(versionIds)) {
    		//删除
    		int count = dmDmSupplyConfirmReportMapper.deleteConfirmReportMonth(yearMonth,projectId);
    		int count2 = dmDmSupplyConfirmReportMapper.deleteConfirmReport(yearMonth,projectId);
    		
    		//所有版本详情
    		long vdStart = System.currentTimeMillis();
        	List<SupplyPlanVersionDetail> versionDataList = supplyPlanVersionDetailMapper.selectVersionDetailList(versionIds,IsDeleteEnum.NO.getKey());
        	long vdEnd = System.currentTimeMillis();
    		log.info("###############获取供货版本详情数据耗时（毫秒）: "+ (vdEnd-vdStart));
    		
    		//去除不需要确认供货的项目信息
    		long hStart = System.currentTimeMillis();
        	List<SupplyPlanVersionDto> resSupplyPlanVersionList = prepareVersionList(supplyPlanVersionList,versionDataList);
        	long hEnd = System.currentTimeMillis();
    		log.info("###############去除不需要确认供货的项目信息耗时（毫秒）: "+ (hEnd-hStart));
    		
    		long cStart = System.currentTimeMillis();
        	List<SupplyConfirmRecord> confirmRecordList =  supplyConfirmRecordMapper.selectConfirmRecordList(yearMonth,IsDeleteEnum.NO.getKey());
        	long cEnd = System.currentTimeMillis();
    		log.info("###############项目确认信息耗时（毫秒）: "+ (cEnd-cStart));
    		
    		if(CollectionUtils.isNotEmpty(resSupplyPlanVersionList)) {
    			for(SupplyPlanVersionDto supplyPlanVersion : resSupplyPlanVersionList) {
    				String versionId = supplyPlanVersion.getId();
            		String versionName = prepareVersionName(supplyPlanVersion);
            		
            		String projectPmUser = getProjectPmUser(supplyPlanVersion.getProjectId());
            		SupplyConfirmRecord record = getSupplyConfirmRecord(supplyPlanVersion.getProjectId(),confirmRecordList);
            		//年度
            		SupplyPlanValueDetailDto yearData = prepareAllYearData(versionId,year,versionDataList);
            		
            		DmDmSupplyConfirmReport confirmReport = new DmDmSupplyConfirmReport();
            		
            		String id = UUIDUtils.create();
            		
        			confirmReport.setId(id);
        			confirmReport.setAffiliationMonth(yearMonth);
        			confirmReport.setVersionId(versionId);
        			confirmReport.setVersionName(versionName);
        			confirmReport.setProjectId(supplyPlanVersion.getProjectId());
        			confirmReport.setProjectCode(supplyPlanVersion.getProjectCode());
        			confirmReport.setProjectName(supplyPlanVersion.getProjectName());
        			confirmReport.setProjectfId(supplyPlanVersion.getProjectfId());
        			confirmReport.setProjectfCode(supplyPlanVersion.getStageCode());
        			confirmReport.setProjectfName(supplyPlanVersion.getStageName());
        			confirmReport.setCreateTime(LocalDateTime.now());
        			confirmReport.setUpdateTime(LocalDateTime.now());
        			
        			if(record != null) {
        				if(record.getConfirmStatus() != null && record.getConfirmStatus().intValue() == 1) {
        					confirmReport.setConfirmStatus(record.getConfirmStatus());
            			}else {
            				confirmReport.setConfirmStatus(0);
            			}
        				confirmReport.setConfirmUserName(record.getConfirmUserName());
            			confirmReport.setPrincipal(record.getPrincipal());
            			confirmReport.setConfirmTime(record.getConfirmTime());
        			}else {
        				confirmReport.setPrincipal(projectPmUser);
        			}
        			
            		//年度
        			confirmReport.setPlanStallNum(yearData.getParkingNum());
        			confirmReport.setPlanRoomNum(yearData.getRoomNum());
        			confirmReport.setPlanArea(yearData.getArea());
        			confirmReport.setPlanStallPrice(yearData.getNotCommodityValue());
        			confirmReport.setPlanRoomPrice(yearData.getHouseCommodityValue());
        			confirmReport.setActualStallNum(yearData.getParkingNumActual());
        			confirmReport.setActualRoomNum(yearData.getRoomNumActual());
        			confirmReport.setActualArea(yearData.getAreaActual());
        			confirmReport.setActualStallPrice(yearData.getNotCommodityValueActual());
        			confirmReport.setActualRoomPrice(yearData.getHouseCommodityValueActual());
            		
        			List<DmDmSupplyConfirmReportMonth> dataList =  Collections.synchronizedList(new ArrayList<>());
            		//月度
            		for(String month : months) {
            			DmDmSupplyConfirmReportMonth confirmReportMonth = new DmDmSupplyConfirmReportMonth();
            			SupplyPlanValueDetailDto monthData = prepareAllMonthData(versionId,month,versionDataList);
            			//月度
            			confirmReportMonth.setId(UUIDUtils.create());
            			confirmReportMonth.setPkId(id);
            			confirmReportMonth.setAffiliationMonth(yearMonth);
            			confirmReportMonth.setShowMonth(month);
            			confirmReportMonth.setStallNum(monthData.getParkingNum());
            			confirmReportMonth.setRoomNum(monthData.getRoomNum());
            			confirmReportMonth.setArea(monthData.getArea());
            			confirmReportMonth.setStallPrice(monthData.getNotCommodityValue());
            			confirmReportMonth.setRoomPrice(monthData.getHouseCommodityValue());
            			confirmReportMonth.setCreateTime(LocalDateTime.now());
            			confirmReportMonth.setUpdateTime(LocalDateTime.now());
            			
            			dataList.add(confirmReportMonth);
            		}
            		
            		//保存
            		dmDmSupplyConfirmReportMapper.insert(confirmReport);
            		
            		dmDmSupplyConfirmReportMapper.insertBatch(dataList);
    			}
    		}
    	}
    	
	}
	
	private String getProjectPmUser(String projectId) {
		StringBuilder sb = new StringBuilder();
		String squ = "";
		HashSet<GroupUserVo> set = idmUserService.getGroupUserInfo(Constants.PROJECT_OPERATION_PM,projectId);
		for(GroupUserVo vo : set) {
			sb.append(squ).append(vo.getUsercn());
			squ ="、";
		}
		return sb.toString();
	}
	
	
	private SupplyConfirmRecord getSupplyConfirmRecord(String projectId, List<SupplyConfirmRecord> confirmRecordList) {
		if(CollectionUtils.isNotEmpty(confirmRecordList)) {
			for(SupplyConfirmRecord obj : confirmRecordList) {
				if(obj.getProjectId().equals(projectId)) {
					return obj;
				}
			}
		}
		return null;
	}
	
	private List<String> getSupplyConfirmDetailMonths(String showMonth) {
		int year = Integer.parseInt(showMonth.split("-")[0]);
		int month = Integer.parseInt(showMonth.split("-")[1]);
		List<String> months = Collections.synchronizedList(new ArrayList<>());
		if (month == Constants.TWELVE) {
			year = year + 1;
			for (int i = 1; i <= Constants.TWELVE; i++) {
				if (i < 10) {
					months.add(year + "-" + "0" + i);
				} else {
					months.add(year + "-" + i);
				}
			}
		} else {
			for (int i = month; i <= Constants.TWELVE; i++) {
				if (i < 10) {
					months.add(year + "-" + "0" + i);
				} else {
					months.add(year + "-" + i);
				}
			}
		}
		return months;
	}
	
	private List<SupplyPlanVersionDto> prepareVersionList(List<SupplyPlanVersionDto> supplyPlanVersionList,List<SupplyPlanVersionDetail> versionDataList) {
		List<SupplyPlanVersionDto> resList = Collections.synchronizedList(new LinkedList<>());
		Set<String> projectList = new TreeSet<String>();
		for(SupplyPlanVersionDto version : supplyPlanVersionList) {
			boolean flag = isAllSupply(version.getId(),versionDataList);
			if(!flag) {
				projectList.add(version.getProjectId());
			}
		}
		if(CollectionUtils.isNotEmpty(projectList)) {
			for(String projectId : projectList) {
				for(SupplyPlanVersionDto version : supplyPlanVersionList) {
					if(projectId.equals(version.getProjectId())) {
						resList.add(version);
					}
				}
				
			}
		}
		return resList;
	}
	
	private boolean isAllSupply(String versionId,List<SupplyPlanVersionDetail> versionDataList) {
		for(SupplyPlanVersionDetail detail : versionDataList) {
			if(detail.getVersionId().equals(versionId)) {
				if(detail.getType().equals(OrgTypeEunm.ORG_BUILD.getKey())) {
					Integer isSupply = detail.getIsSupply();
					String bussinessType = detail.getBusinessType();
					if(bussinessType.equals(SalyTypeEnum.SALABLE.getKey()) || bussinessType.equals(SalyTypeEnum.STAGE_SELF_SUSTAINMENT.getKey()) ) {
						if(isSupply != null && isSupply.intValue() == 0) {
							return false;
						}
					}
				}
			}
		}
		return true;
	}
	
	private String prepareVersionName(SupplyPlanVersionDto supplyPlanVersion) {
		String versionName="";
		String versionType = supplyPlanVersion.getVersionType();
		String versionTypeName = VersionTypeEunm.getValueByKey(versionType);
		String vesionNum = supplyPlanVersion.getVersionNum();
		String lastDate = "";
		if(supplyPlanVersion.getUpdateTime() != null) {
			lastDate = LocalDateTimeUtils.formatTime(supplyPlanVersion.getUpdateTime(), "yyyyMMdd");
		}else {
			lastDate = LocalDateTimeUtils.formatTime(supplyPlanVersion.getCreateTime(), "yyyyMMdd");
		}
		if(versionType.equals(VersionTypeEunm.INVESTMENT.getKey()) || versionType.equals(VersionTypeEunm.WARPLAN.getKey())) {
			String assessmentTag="";
			Integer isAssessmentVersion = supplyPlanVersion.getIsAssessmentVersion();
			if(isAssessmentVersion != null && isAssessmentVersion.intValue() == 1) {
				assessmentTag = "(考核版)";
			}
			versionName = versionTypeName+vesionNum+"-"+lastDate+assessmentTag;
		}else if(versionType.equals(VersionTypeEunm.BUDGET.getKey())) {
			String budgetYear = supplyPlanVersion.getBudgetYear();
			String versionIdentifyName = VersionIdentifyEnum.getValueByKey(supplyPlanVersion.getVersionIdentify());
			versionName = budgetYear+versionIdentifyName+"预算版"+vesionNum+"-"+lastDate;
		}else {
			String affiliationMonth = supplyPlanVersion.getAffiliationMonth();
			if(StrUtils.isNotEmpty(affiliationMonth)) {
				affiliationMonth = affiliationMonth.replace("-","");
			}
			versionName = affiliationMonth+"月动态版"+vesionNum+"-"+lastDate;
		}
		return versionName;
	}

}
